/*
 * Stations.java
 *
 * Created on June 9, 2007, 7:21 PM
 *
 * Copyright 2008 David D. Emory
 * 
 * This file is part of Five Points. See <http://www.fpdev.org> for
 * additional information regarding the project.
 * 
 * Five Points is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Five Points is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Five Points.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.fpdev.core.transit;

import java.io.FileWriter;
import java.util.Collection;
import java.util.Iterator;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.fpdev.core.FPEngine;
import org.fpdev.core.basenet.BLink;
import org.fpdev.core.basenet.BNode;
import org.fpdev.apps.rtemaster.GUIOutputAcceptor;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * A collection of Station objects. Handles I/O for the stations.xml file.
 *
 * @author demory
 */
public class Stations {

  private FPEngine engine_;
  private SortedMap<String, Station> stations_;
  private String filename_;

  private boolean xmlFileSaved_;

  /** Creates a new instance of Stations */
  public Stations(FPEngine engine) {
    engine_ = engine;
    stations_ = new TreeMap<String, Station>();
    filename_ = null;
  }

  public void initNetworkElements() {
    for(Station sta : stations_.values())
      sta.initNetworkElements(engine_.getBaseNet());
  }

  public boolean isXMLFileSaved() {
    return xmlFileSaved_;
  }

  public void changesMade() {
    xmlFileSaved_ = false;
  }

  public void readFromXML(String filename) {
    filename_ = filename;
    try {
      DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
      Document doc = docBuilder.parse(filename);
      NodeList docNodes = doc.getChildNodes();
      Node thisNode = docNodes.item(0);
      if (docNodes.getLength() != 1 && !thisNode.getNodeName().equals("fivepoints")) {
        System.out.println("Not a valid Five Points datafile");
        return;
      }

      docNodes = thisNode.getChildNodes();

      for (int i = 0; i < docNodes.getLength(); i++) {
        thisNode = docNodes.item(i);
        String name = thisNode.getNodeName();
        //System.out.println("xmlnode: "+thisNode.getNodeName());
        if (name.equals("stations")) {
          NodeList nodes = thisNode.getChildNodes();
          for (int ni = 0; ni < nodes.getLength(); ni++) {
            Node stationNode = nodes.item(ni);
            if (stationNode.getNodeName().equals("station")) {
              //System.out.println("processing node");
              NamedNodeMap attributes = stationNode.getAttributes();
              String id = attributes.getNamedItem("id").getNodeValue();
              String sname = attributes.getNamedItem("name").getNodeValue();
              Station stationElement = new Station(id, sname);
              NodeList subNodes = stationNode.getChildNodes();
              for (int sni = 0; sni < subNodes.getLength(); sni++) {
                Node subNode = subNodes.item(sni);
                if (subNode.getNodeName().equals("snode")) {
                  attributes = subNode.getAttributes();
                  Integer snodeID = new Integer(attributes.getNamedItem("id").getNodeValue());
                  String nname = attributes.getNamedItem("name").getNodeValue();
                  /*BNode snode = engine_.getNodeFromID(snodeID);
                  if (snode == null) {
                    System.out.println("Invalid station node w/ id=" + snodeID);
                  } else {
                    stationElement.addNode(snode, nname);
                  }*/
                  stationElement.addNode(snodeID, name);
                }
                if (subNode.getNodeName().equals("slink")) {
                  attributes = subNode.getAttributes();
                  Integer slinkID = new Integer(attributes.getNamedItem("id").getNodeValue());
                  /*BLink slink = engine_.getLinkFromID(slinkID);
                  if (slink == null) {
                    System.out.println("Error loading station link with id " + slinkID);
                  } else {
                    stationElement.addLink(slink);
                  }*/
                  stationElement.addLink(slinkID);
                }
              }
              add(stationElement);
            }
          }
        }
      }
      xmlFileSaved_ = true;
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void writeFile(GUIOutputAcceptor guiOA) {
    try {
      Iterator<Station> stations = iterator();
      int totalItems = count(), numWritten = 0, pctWritten = 0, oldPctWritten;
      FileWriter writer = new FileWriter(filename_);
      writer.write("<?xml version=\"1.0\"?>\n");
      writer.write("<fivepoints>\n");
      writer.write("<stations>\n");
      while (stations.hasNext()) {
        Station station = stations.next();
        writer.write("<station id=\"" + station.getID() + "\" name=\"" + station.getName() + "\">\n");

        // write nodes
        for(BNode snode : station.getNodes()) {
          writer.write("<snode id=\"" + snode.getID() + "\" name=\"" + station.getNodeName(snode) + "\" />\n");
        }

        // write links
        for(BLink slink : station.getLinks()) {
          writer.write("<slink id=\"" + slink.getID() + "\" />\n");
        }

        writer.write("</station>\n");

        // update progress bar
        numWritten++;
        oldPctWritten = pctWritten;
        double pctWrittenD = 100.0 * (double) numWritten / (double) totalItems;
        pctWritten = (int) pctWrittenD;
        if (pctWritten != oldPctWritten && guiOA != null) {
          guiOA.setProgress(pctWritten);
        }

      }
      writer.write("</stations>\n");
      writer.write("</fivepoints>\n");
      writer.close();
      xmlFileSaved_ = true;
      guiOA.setProgress(0);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public Station getFromIndex(int index) {
    if (index < 0 || index >= count()) {
      return null;
    }
    Iterator<Station> iter = iterator();
    for (int i = 0; i < index; i++) {
      iter.next();
    }
    return iter.next();
  }

  public int indexOf(Station station) {
    Iterator<Station> iter = iterator();
    int i = 0;
    while (iter.hasNext()) {
      if (iter.next() == station) {
        return i;
      }
      i++;
    }
    return -1;
  }

  public void add(Station station) {
    stations_.put(station.getID(), station);
    xmlFileSaved_ = false;
  }

  public void remove(String id) {
    stations_.remove(id);
    xmlFileSaved_ = false;
  }

  public int count() {
    return stations_.size();
  }

  public Collection<Station> getCollection() {
    return stations_.values();
  }

  public Iterator<Station> iterator() {
    return stations_.values().iterator();
  }
}
